package me.ahoukuse.koala.util;

import com.alibaba.fastjson2.JSONObject;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.UUID;

public class FileUtil {
    public static boolean persistMultipartFile(MultipartFile multipartFile, File file)  {
        InputStream inputStream = null;
        OutputStream outputStream = null;
        boolean success = false;
        try {
            inputStream = multipartFile.getInputStream();
            outputStream = new FileOutputStream(file);
            byte[] buffer = new byte[8192];
            int bytesRead = 0;
            while ((bytesRead = inputStream.read(buffer, 0, buffer.length)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            success = true;
        } catch (IOException notFoundException) {
            notFoundException.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return success;
    }

    public static JSONObject persistMultipartFile(MultipartFile multipartFile, String prefix)  {
        if (multipartFile != null) {
            String extName = getFileExtension(multipartFile.getOriginalFilename());
            String uuid = UUID.randomUUID().toString();

            File file = new File(prefix+uuid+"."+extName);

            JSONObject res = new JSONObject();
            boolean success = persistMultipartFile(multipartFile, file);
            res.put("success", success);
            res.put("fileName", uuid+"."+extName);
            return res;
        } else {
            JSONObject res = new JSONObject();
            res.put("success", false);
            return res;
        }
    }

    public static JSONObject persistMultipartFile(MultipartFile multipartFile)  {
        String prefix = "D:\\MyProject\\koala\\upload\\";
        String extName = getFileExtension(multipartFile.getOriginalFilename());
        String uuid = UUID.randomUUID().toString();

        File file = new File(prefix+uuid+"."+extName);

        JSONObject res = new JSONObject();
        boolean success = persistMultipartFile(multipartFile, file);
        res.put("success", success);
        res.put("fileName", uuid+"."+extName);
        return res;
    }

    public static String getFileExtension(String fileName) {
        if (fileName == null || fileName.isEmpty()) {
            throw new IllegalArgumentException("文件名不能为空");
        }

        int lastDotIndex = fileName.lastIndexOf('.');

        if (lastDotIndex == -1 || lastDotIndex == fileName.length() - 1) {
            return "";
        }

        return fileName.substring(lastDotIndex + 1);
    }

    public static int getFileType(String fileName) {
        String extName = getFileExtension(fileName);
        if ("doc".equalsIgnoreCase(extName) || "docx".equalsIgnoreCase(extName)) {
            return 2;
        } else if ("txt".equalsIgnoreCase(extName) || "text".equalsIgnoreCase(extName)) {
            return 1;
        } else {
            return 0;
        }
    }

    public static String encodeImageToBase64(BufferedImage image) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(image, "png", baos);

        byte[] imageBytes = baos.toByteArray();
        return Base64.getEncoder().encodeToString(imageBytes);
    }


    /**
     * 移动文件
     *
     * @param sourcePath 原始文件路径
     * @param targetPath 目标文件路径
     * @throws IOException 如果发生I/O异常
     */
    public static void moveFile(String sourcePath, String targetPath) throws IOException {
        Path source = Path.of(sourcePath);
        Path target = Path.of(targetPath);

        try {
            Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);
            System.out.println("File moved successfully.");
        } catch (FileAlreadyExistsException e) {
            // 如果目标文件已存在，进行替换
            Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
            Files.delete(source);
            System.out.println("File replaced successfully.");
        }
    }


    /**
     * 获取文件大小
     *
     * @param filePath 文件路径
     * @return 文件大小，以字节为单位
     * @throws IOException 如果发生I/O异常
     */
    public static long getFileSize(String filePath) throws IOException {
        Path path = Path.of(filePath);
        return Files.size(path);
    }


    private static final int BUFFER_SIZE = 8192; // 缓冲区大小，可以根据实际情况调整

    /**
     * 计算文件的MD5值（逐块读取）
     *
     * @param filePath 文件路径
     * @return 文件的MD5值，以十六进制字符串表示
     * @throws IOException              如果发生I/O异常
     * @throws NoSuchAlgorithmException 如果MD5算法不可用
     */
    public static String calculateMD5(String filePath) throws IOException, NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        try (FileInputStream fis = new FileInputStream(filePath);
             FileChannel channel = fis.getChannel()) {

            ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);

            while (channel.read(buffer) != -1) {
                buffer.flip();
                md.update(buffer);
                buffer.clear();
            }
        }

        // 获取MD5的字节数组
        byte[] mdBytes = md.digest();

        // 将字节数组转换为十六进制字符串
        StringBuilder sb = new StringBuilder();
        for (byte mdByte : mdBytes) {
            sb.append(Integer.toString((mdByte & 0xff) + 0x100, 16).substring(1));
        }

        return sb.toString();
    }
}
